
import functools
from docx.oxml.text.paragraph import CT_P
from docx.oxml.table import CT_Tbl
import re

from docx.text.paragraph import Paragraph
from docx.table import Table
from docx.api import Document


def printchildren(b1, line=[], deep=99):
    line2 = line.copy()
    line2.append(0)
    print(*line2, type(b1))
    for i, b2 in enumerate(b1.iterchildren()):
        line2[-1] = i
        print(line2, type(b2))
        if len(line2) < deep:
            printchildren(b2, line2, deep)


def find_keywords(pattern, pt):
    if isinstance(pattern, str):
        return find_keyword(pattern, pt)
    elif isinstance(pattern, list):
        for ep in pattern:
            value = find_keyword(ep, pt)
            if value != None:
                return value
    return None


def find_keyword(pattern, pt):
    if pattern:
        if isinstance(pt, Paragraph):
            g = re.search(pattern=pattern, string=pt.text)
            if g:
                for v in g.groupdict().values():
                    return v
                return ''
    return None


class Dagangkaitou():
    def __init__(self):
        self.课程编码 = ''


class ReKeyword(object):
    def __init__(self, pattern, obj, attrname, ):
        self.pattern = pattern
        self.attrname = attrname
        self.obj = obj
        self.value = None
        # self.contentlist = contentlist


class Section(object):
    def __init__(self, parentcontent, enter_pattern, leave_pattern=''):
        self.enter_pattern = enter_pattern
        self.leave_pattern = leave_pattern
        self.content = self.fromparent(parentcontent)

    def append(self, pt):
        self.content.append(pt)

    def text(self):
        return [x.text if isinstance(x, Paragraph) else type(x) for x in self.content]

    def fromparent(self, parentcontent):
        enter = False if self.enter_pattern else True
        content = []
        for line, pt in enumerate(parentcontent):
            value = find_keywords(self.enter_pattern, pt)
            if value != None:
                enter = True
            value = find_keywords(self.leave_pattern, pt)
            if value != None:
                enter = False
            if enter:
                content.append(pt)
        return content

    def __str__(self):
        return '%s' % self.text()


class Section课程性质和教学目的(Section):
    def __init__(self, content):
        super().__init__(content, '(课程性质和目标)|(课程性质和教学目的)', '教学内容、要求和学时分配')
        self.课程性质 = Section(self.content, '^课程性质[^和]', '^教学目的')
        self.教学目的 = Section(self.content, '^教学目的')


class SectionChapter(Section):
    def __init__(self):
        self.content = []

    def __str__(self):
        return "%s" % [x.text if isinstance(x, Paragraph) else type(x) for x in self.content]


class Section教学内容要求和学时分配(Section):
    def __init__(self, content):
        super().__init__(content, '教学内容、要求和学时分配', '选用教材')
        self.章节 = []
        sc = None

        for line, pt in enumerate(self.content):
            if line == 0:
                continue
            # print(pt.text if isinstance(pt,Paragraph) else type(pt))
            if find_keywords('学时分配[:：]', pt) != None:
                break
            if find_keywords('学时', pt) != None:
                sc = SectionChapter()
                self.章节.append(sc)
            if sc:
                # print(pt.text)
                sc.content.append(pt)
        self.学时分配 = Section(self.content, '学时分配[:：]')

    def __str__(self):
        return "%s \n %s \n %s \n %s \n %s" % ("="*40, [x.text() for x in self.章节], "="*40, self.学时分配, "="*40, )


class Dagang():
    __slots__ = ('flag', '开头', 'title', 'content', '课程性质和教学目的', '课程性质', '教学目的', '教学内容要求和学时分配', '选用教材', '先修课要求',
                 '先修课要求', '教学手段与建议', '考核方式及成绩评定', '结尾', '课程编码', '课程类别', '学时', '学分', '学时学分', '适用专业', '编写人', '讨论参加人', '审核人')
    '''
        课程教学大纲
        一、课程性质和教学目的
        二、教学内容、要求和学时分配
        三、选用教材
        四、先修课要求
        五、教学手段与建议
        六 、考核方式及成绩评定
        编写人
        '''

    def __init__(self, title):
        self.title = title
        self.content = []
        self.开头 = []
        # self.课程性质和教学目的 = []
        # self.课程性质 = []
        # self.教学目的 = []
        self.教学内容要求和学时分配 = []
        self.选用教材 = []
        self.先修课要求 = []
        self.先修课要求 = []
        self.教学手段与建议 = []
        self.考核方式及成绩评定 = []
        self.结尾 = []
        self.flag = set()

    def append(self, c):
        # print(c)
        self.content.append(c)

    def search_keyword_set_value(self, pattern, attrname, content=None):
        # print(self.content)
        for pt in content if content else self.content:
            value = find_keyword(pattern, pt)
            if value != None:
                setattr(self, attrname, value)
                print(attrname, '=', [value])
                break

    def search_keyword_enter_flag(self, pattern, pt, enter_flag, discard_flag=''):
        value = find_keyword(pattern, pt)
        if value != None:
            self.flag.add(enter_flag)
            if discard_flag:
                self.flag.discard(discard_flag)
            return value
        return None

    def search(self):
        self.search_keyword_set_value(r'【课程编码】(?P<t>\w*)', '课程编码')
        self.search_keyword_set_value(r'【课程类别】(?P<t>\w*)', '课程类别')
        self.search_keyword_set_value(r'【学时学分】(?P<t>\w*)学时', '学时')
        self.search_keyword_set_value(r'【学时学分】\w*学时[,，]?(?P<t>\w*)学分', '学分')
        self.search_keyword_set_value(r'【学时学分】(?P<t>\w*学时[,，]?\w*学分)', '学时学分')
        self.search_keyword_set_value(r'【适用专业】(?P<t>\w*)', '适用专业')
        self.search_keyword_set_value(r'编写人[：:](?P<t>\w*)', '编写人')
        self.search_keyword_set_value(r'讨论参加人[：:](?P<t>\w*)', '讨论参加人')
        self.search_keyword_set_value(r'审核人[：:](?P<t>\w*)', '审核人')
        self.开头 = Section(self.content, '',
                          '(课程性质和目标)|(课程性质和教学目的)')
        self.教学目的 = Section(self.content,
                            '^教学目的([：:]+(?P<t>.*)|[：:]?$)', '教学内容、要求和学时分配')
        self.课程性质和教学目的 = Section课程性质和教学目的(self.content)
        self.课程性质 = self.课程性质和教学目的.课程性质
        self.教学目的 = self.课程性质和教学目的.教学目的
        self.教学内容要求和学时分配 = Section教学内容要求和学时分配(self.content)
        self.选用教材 = Section(self.content, '选用教材', '先修课要求')
        self.先修课要求 = Section(self.content, '先修课要求', '教学手段与建议')
        self.教学手段与建议 = Section(self.content, '教学手段与建议', '考核方式及成绩评定')
        self.考核方式及成绩评定 = Section(self.content, '考核方式及成绩评定', '编写人')
        self.结尾 = Section(self.content, '编写人',                          '')
        # flagset = set()
        for line, pt in enumerate(self.content):
            pass
            # 课程性质 = self.search_keyword_enter_flag(
            #     '^课程性质([：:]+(?P<t>.*)|[：:]?$)', pt, '课程性质')
            # 教学目的 = self.search_keyword_enter_flag(
            #     '^教学目的([：:]+(?P<t>.*)|[：:]?$)', pt, '教学目的', '课程性质')

            # if '课程性质' in self.flag:
            #     if 课程性质 != None:  # 第一行
            #         self.课程性质.append(课程性质)
            #     else:  # 其它行
            #         self.课程性质.append(pt.text)

            # 课程性质 = self.find_keyword(
            #     '^课程性质(([：:]+(?P<t>.*))|$)', pt)
            # if 课程性质 != None:
            #     flagset.add('课程性质')
            #     if 课程性质:
            #         self.课程性质.append(课程性质)
            #     self.课程性质和教学目的.append(pt)

            # 教学内容 = self.find_keyword(
            #     '教学内容、要求和学时分配', pt)
            # if 教学内容 != None:
            #     flagset.discard('教学目标')
            #     flagset.add('教学内容')

            # 选用教材 = self.find_keyword(
            #     '选用教材', pt)
            # if 教学内容 != None:
            #     flagset.discard('教学内容')
            #     flagset.add('选用教材')

            # 先修课要求 = self.find_keyword(
            #     '先修课要求', pt)
            # if 先修课要求 != None:
            #     flagset.discard('选用教材')
            #     flagset.add('先修课要求')

            # 教学手段与建议 = self.find_keyword(
            #     '教学手段与建议', pt)
            # if 教学手段与建议 != None:
            #     flagset.discard('先修课要求')
            #     flagset.add('教学手段与建议')

            # 考核方式及成绩评定 = self.find_keyword(
            #     '教学手段与建议', pt)
            # if 考核方式及成绩评定 != None:
            #     flagset.discard('教学手段与建议')
            #     flagset.add('考核方式及成绩评定')
            # self.search_keyword_enter_flag('编写人[：:]', pt, '编写人', '考核方式及成绩评定')
            # 编写人 = self.find_keyword(
            #     '编写人[：:]', pt)
            # if 编写人 != None:
            #     flagset.discard('考核方式及成绩评定')
            #     flagset.add('编写人')

            # if '教学目标' in flagset and 教学目的 == None:
            #     self.教学目的.append(pt)
            #     self.课程性质和教学目的.append(pt)
            # if '课程性质' in flagset and 课程性质 == None:
            #     self.课程性质和教学目的.append(pt)
            #     self.课程性质.append(pt.text)

            # if '教学内容' in flagset:
            #     pass

    def check(self):
        print(self.title)
        self.search()
        # print(self.content)
        if len(self.开头.content) == 0:
            raise ValueError()
        print(self.开头)
        print(self.课程性质)
        print(self.教学目的)
        print(self.教学内容要求和学时分配)
        print(self.选用教材)
        print(self.先修课要求)
        print(self.教学手段与建议)
        print(self.考核方式及成绩评定)
        print(self.结尾)
        # print([x.text for x in self.教学目的.content if ])


class DagangDoc(object):
    def __init__(self, filename, *args, **kwargs):
        self.DgList = []
        self.line = -1
        self.dagang = None
        self.doc = Document(filename)
        self.initDagangList()

    def is_new_dagang(self, p):
        g = re.search(r'[《]?(?P<t>\w*)[》]?(实验)?课程教学大纲', p.text)
        title = g.group('t') if g and g.group('t') else None

        if title:
            if self.dagang:
                self.dagang.check()
                # break
            self.dagang = Dagang(title)
            # print(self.line, title)
            self.dagang.append(p)
            self.DgList.append(self.dagang)

    def initDagangList(self):
        body = self.doc.element.body
        # dagang = None
        for i, b1 in enumerate(body.iterchildren()):
            self.line = i
            if i > 245:
                break
            if isinstance(b1, CT_P):
                p = Paragraph(b1, body)
                self.is_new_dagang(p)
                if self.dagang:
                    self.dagang.append(p)

            elif isinstance(b1, CT_Tbl):
                t = Table(b1, body)
                if self.dagang:
                    self.dagang.append(t)
            else:
                print(i, '未处理类型' * 10, type(b1))
                # printchildren(b1)
                pass

        if self.dagang:
            self.dagang.check()


if __name__ == "__main__":
    doc = DagangDoc("d:\\专业选修课.docx")
